home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
drdobbs
/
1990
/
06
/
allen.lst
< prev
next >
Wrap
File List
|
1990-05-02
|
10KB
|
428 lines
_A PIXEL ORDERING ALGORITHM_
by Norton T. Allen
[LISTING ONE]
/* points.c Copyright (c) 1989 by Norton T. Allen */
#include "points.h"
int nbits(int i) {
int nb;
for (nb = 0; i != 0; nb++) i >>= 1;
return(nb);
}
static int focus_x, focus_y, focus_width, focus_height;
/* zeros in map correspond to x bits, 1's to y bits */
static long int z, map, zlim;
static int tbits, xor_y;
void init_points(int left, int top, int width, int height) {
int nbits_w, nbits_h;
long int mask;
focus_x = left;
focus_y = top;
focus_width = width;
focus_height = height;
nbits_w = nbits(focus_width);
nbits_h = nbits(focus_height);
tbits = nbits_w + nbits_h;
xor_y = nbits_w < nbits_h;
z = 0L;
zlim = 1L << tbits;
map = 0L;
for (mask = 1L; nbits_w || nbits_h; ) {
if (nbits_w > nbits_h || (nbits_w == nbits_h && xor_y)) {
nbits_w--;
mask <<= 1;
}
if (nbits_h > 0 &&
(nbits_h > nbits_w || (nbits_w == nbits_h && !xor_y))) {
nbits_h--;
map |= mask;
mask <<= 1;
}
}
}
int next_point(int *dx, int *dy) {
int x, y, n;
long int m, rz;
for (;;) {
if (z == zlim) return(1);
m = map; rz = z; n = tbits;
x = y = 0;
while (n-- > 0) {
if (m & 1) { /* this is a ybit */
y <<= 1;
if (rz & 1) y++;
} else {
x <<= 1;
if (rz & 1) x++;
}
m >>= 1; rz >>= 1;
}
z++;
if (xor_y) y = x ^ y;
else x = x ^ y;
if (x >= focus_width) continue;
if (y >= focus_height) continue;
break;
}
*dx = x + focus_x;
*dy = y + focus_y;
return(0);
}
[LISTING TWO]
/* mandel.c will handle the actual Mandelbrot set calculations.
Copyright (c) 1989 by Norton T. Allen */
#include "grafix.h"
/* This is the aspect ratio calculated on my screen: */
#define ASPECT 0.739
static double xscale, yscale, xo, yo;
/* set_range() is similar to setcoords() except that it guarantees
equal x and y scales, taking the aspect ratio into account.
The axis with the smaller scale is adjust so the specified
range will be centered on the screen. Another reason for
not using setcoords() is that I need the inverse functions
mapping device coordinates to virtual coordinates.
*/
void set_range(double xmin, double ymin, double xmax, double ymax) {
double delta;
yscale = (ymax-ymin)/vp_height();
xscale = (xmax-xmin)/vp_width();
if (yscale*ASPECT > xscale) {
xscale = yscale*ASPECT;
delta = (xmin + xscale * vp_width() - xmax)/2.;
xmin -= delta;
xmax += delta;
} else {
yscale = xscale/ASPECT;
delta = (ymin + yscale * vp_height() - ymax)/2.;
ymin -= delta;
ymax += delta;
}
xo = xmin;
yo = ymin;
} /* ---------------------------------------------------------------- */
double vx (int dx) /* convert device x to virtual x */
{
return ((double) dx * xscale + xo);
} /* ---------------------------------------------------------------- */
double vy (int dy) /* convert device y to virtual y */
{
return ((double) dy * yscale + yo);
} /* ---------------------------------------------------------------- */
/* Membership in the Mandelbrot set is determined by an
iterative function. Given the complex starting
coordinate C the function is:
Z(0) = 0.
Z(n+1) = Z(n)^2 + C
A point is deemed to be in the set if NLOOP iterations fails
to produce a point with absolute value greater than LIMIT.
Points within the set are colored black. Points outside the
set are colored based on how many iterations passed before
exceeding LIMIT. Miriad other schemes are possible. Other
values for NLOOP and LIMIT are probably desirable, depending
on how deep you go.
*/
#define NLOOP 100
#define LIMIT 10000.
#define NCOLORS 15
int mandel_color(double cx, double cy) {
int k;
double zx, zy, zx2, zy2;
zx = zy = 0.;
for (k = 0; k < NLOOP; k++) {
zx2 = zx*zx;
zy2 = zy*zy;
if (zx2+zy2 > LIMIT) break;
zy = 2*zx*zy + cy;
zx = zx2 - zy2 + cx;
}
if (k < NLOOP) return((k % NCOLORS)+1);
return(0);
}
[LISTING THREE]
/* generate.c Copyright (c) 1989 by Norton T. Allen */
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include "points.h"
#include "grafix.h"
/* This structure defines a rectangular box which we can move around the
screen using the cursor keys. fbox.on is TRUE if the box is
currently displayed. fbox.mode takes the values:
0 Not active
1 Cursor keys move the whole box
2 Cursor keys change box's size
*/
struct bx {
int x, y, dx, dy, on, mode;
} fbox = {300, 160, 50, 40, 0, 0};
void flip_box(void) {
set_write_mode(WM_XOR);
set_color1(15);
draw_rect(fbox.x, fbox.y, fbox.dx, fbox.dy);
set_write_mode(WM_REPLACE);
fbox.on = !fbox.on;
}
void help(void) {
printf("'Esc' to exit\n");
printf("? for this message\n");
printf("m to move the focus box.(use cursor keys)\n");
printf("s to size the focus box.(use cursor keys)\n");
printf("f to focus on the focus area\n");
printf("z to zoom in on the focus area\n");
getch();
}
static int dm = 1; /* How many pixels to move with each cursor step */
/* check_box makes sure the new box meets the following requirements:
1. It isn't off the screen.
2. It's not smaller then 2 pixels in either dimension
Check box turns off the old box, but leaves the new box off also;
menu() will turn it on when there's no more keyboard input.
*/
void check_box(struct bx *nb) {
if (nb->x < 0 || nb->y < 0 ||
nb->x + nb->dx > vp_width() ||
nb->y + nb->dy > vp_height() ||
nb->dx < 2 || nb->dy < 2 ||
(nb->x == fbox.x && nb->y == fbox.y &&
nb->dx == fbox.dx && nb->dy == fbox.dy))
return;
if (fbox.on) flip_box();
fbox = *nb;
fbox.on = 0;
}
/* These are scan codes for cursor keys: */
#define EX_UP 72
#define EX_DOWN 80
#define EX_RIGHT 77
#define EX_LEFT 75
/* Menu supports the following keys:
ESC Exit
M suspend calculations and put box on the screen in
mode 1 for 'moving'.
S As with M, but mode 2 for 'sizing'.
C Remove box and continue calculations as before
F Focus on boxed region.
Z Zoom in on boxed region.
Cursor keys Move or size box
0-9 Change step size for cursor keys
*/
void menu(void) {
int c;
struct bx new_box;
double xmin, ymin, xmax, ymax;
for (;;) {
while (kbhit()) {
c = getch();
switch (c) {
case '\033':
exit(0);
case 'c':
case 'C':
fbox.mode = 0;
break;
case 'm':
case 'M':
fbox.mode = 1;
break;
case 's':
case 'S':
fbox.mode = 2;
break;
case 'f': /* Focus on boxed region */
case 'F':
if (fbox.mode == 0) break;
init_points(fbox.x, fbox.y, fbox.dx, fbox.dy);
fbox.mode = 0;
break;
case 'z': /* Zoom in on boxed region */
case 'Z':
if (fbox.mode == 0) break;
xmin = vx(fbox.x);
ymin = vy(fbox.y+fbox.dy);
ymax = vy(fbox.y);
xmax = vx(fbox.x+fbox.dx);
set_range(xmin, ymin, xmax, ymax);
init_points(0, 0, vp_width(), vp_height());
pc_textmode(); /* Kluge to clear screen */
init_video(EGA);
fbox.mode = fbox.on = 0;
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
dm = c-'0';
break;
case 0:
c = getch();
new_box = fbox;
if (fbox.mode == 1) { /* moving the box */
switch (c) {
case EX_UP:
new_box.y -= dm;
break;
case EX_DOWN:
new_box.y += dm;
break;
case EX_RIGHT:
new_box.x += dm;
break;
case EX_LEFT:
new_box.x -= dm;
break;
default: break;
}
} else if (fbox.mode == 2) {
switch (c) {
case EX_UP:
new_box.dy -= dm;
break;
case EX_DOWN:
new_box.dy += dm;
break;
case EX_RIGHT:
new_box.dx += dm;
break;
case EX_LEFT:
new_box.dx -= dm;
break;
default: break;
}
}
check_box(&new_box);
break;
default:
break;
}
}
if (fbox.mode == 0) break;
else if (!fbox.on) flip_box();
}
if (fbox.on) flip_box();
}
/* Generate cycles through all the pixels, possibly starting over as
dictated by menu(). Generate never returns.
*/
void generate(void) {
int c, x, y;
double fx, fy;
for (;;) {
while (next_point(&x, &y) == 0) {
fx = vx(x);
fy = vy(y);
c = mandel_color(fx, fy);
set_color1(c);
draw_point(x, y);
if (kbhit()) menu();
}
menu();
}
}
void main(int argc, char **argv) {
if (init_video (EGA)) {
init_points(0, 0, vp_width(), vp_height());
set_range(-2., -.95, .75, .95);
generate();
} else printf("Cannot select graphics mode");
}
[LISTING FOUR]
/* points.h include file for pixel ordering program. */
void init_points(int left, int top, int width, int height);
int next_point(int *dx, int *dy);
int mandel_color(double cx, double cy);
void set_range(double xmin, double ymin, double xmax, double ymax);
double vx (int dx); /* convert device x to virtual x */
double vy (int dy); /* convert device y to virtual y */
[LISTING FIVE]
To be included in grafix.h
/* Added by Norton Allen */
/* --------------------- */
void set_write_mode(int mode);
#define WM_REPLACE 0
#define WM_XOR 0x18
[LISTING SIX]
/* wmode.c for DDJ grafix library Copyright (c) 1989 by Norton T. Allen */
#include <dos.h>
#include "grafix.h"
int write_mode = WM_REPLACE;
void set_write_mode(int mode) {
write_mode = mode;
}